package com.luo.ams.service.impl;


import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.luo.ams.mapper.AdminMapper;
import com.luo.ams.mapper.AdminRoleMapper;
import com.luo.ams.mapper.RoleMapper;
import com.luo.ams.security.AdminLoginInfoVo;
import com.luo.ams.security.AdminLoginPrincipal;
import com.luo.ams.security.AdminUserDetails;
import com.luo.ams.service.IAdminService;
import com.luo.common.exception.BBSServiceException;
import com.luo.common.restful.ResponseCode;
import com.luo.pojo.ams.dto.AdminAddDTO;
import com.luo.pojo.ams.dto.AdminLoginDTO;
import com.luo.pojo.ams.entity.Admin;
import com.luo.pojo.ams.entity.AdminRole;
import com.luo.pojo.ams.entity.Role;
import com.luo.pojo.ams.vo.AdminInfoVO;
import com.luo.pojo.ums.entity.User;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.*;

/**
 * <p>
 * 管理员表 服务实现类
 * </p>
 *
 * @author bin.cn
 * @since 2023-01-19
 */
@Service
@Slf4j
public class AdminServiceImpl extends ServiceImpl<AdminMapper, Admin> implements IAdminService {
    @Autowired
    private AdminMapper adminMapper;
    @Autowired
    private AuthenticationManager authenticationManager;
    @Autowired
    private PasswordEncoder passwordEncoder;
    @Autowired
    private RoleMapper roleMapper;
    @Autowired
    private AdminRoleMapper adminRoleMapper;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Value("${jwt.secretKey}")
    private String secretKey;
    @Value("${jwt.tokenHead}")
    private String tokenHead;
    @Value("${jwt.logoutKey}")
    private String logoutKey;

    @Override
    public String login(AdminLoginDTO adminLoginDTO) {
        Authentication authentication = new UsernamePasswordAuthenticationToken(
                adminLoginDTO.getUsername(), adminLoginDTO.getPassword()
        );
        Authentication authenticate = authenticationManager.authenticate(authentication);
        AdminUserDetails infoVo = (AdminUserDetails) authenticate.getPrincipal();
        //生成jwt
        Map<String, Object> claims = new HashMap<>();
        claims.put("id", infoVo.getId());
        claims.put("username", infoVo.getUsername());
        //转化为json对象
        Collection<GrantedAuthority> authorities = infoVo.getAuthorities();
        String jsonString = JSON.toJSONString(authorities);
        claims.put("authorities", jsonString);

        String jwt = Jwts.builder()
                .setHeaderParam("alg", "HS256")
                .setHeaderParam("typ", "jwt")
                .setClaims(claims)
                .signWith(SignatureAlgorithm.HS256, secretKey)
                .setExpiration(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 24 * 7))
                .compact();
        //修改上次登录时间
        LocalDateTime now = LocalDateTime.now();
        Admin admin = adminMapper.selectById(infoVo.getId());
        admin.setGmtLastLogin(now);
        adminMapper.updateById(admin);
        log.debug("返回的内容是:{}", jwt);
        return jwt;
    }

    @Override
    public void logout(String token) {
        if (StringUtils.isBlank(token) || !token.startsWith(tokenHead)){
            throw new BBSServiceException(ResponseCode.FORBIDDEN,"证书不合法");
        }
        String authToken = token.substring(tokenHead.length());
        if (StringUtils.isBlank(authToken)||authToken.length()<60){
            throw new BBSServiceException(ResponseCode.FORBIDDEN,"证书不合法");
        }
        Long add = stringRedisTemplate.boundSetOps(logoutKey).add(authToken);
        if (add==0){
            throw new BBSServiceException(ResponseCode.BAD_REQUEST, "当前用户已登出，请勿重复登出!");
        }
        SecurityContextHolder.clearContext();
    }

    @Override
    public AdminInfoVO getInfo() {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        AdminLoginPrincipal principal = (AdminLoginPrincipal) authentication.getPrincipal();
        if (principal == null) {
            throw new BBSServiceException(ResponseCode.UNAUTHORIZED, "没有登录！");
        }
        Long id = principal.getId();
        Admin admin = adminMapper.selectById(id);
        AdminInfoVO adminInfoVO = new AdminInfoVO();
        BeanUtils.copyProperties(admin, adminInfoVO);
        return adminInfoVO;
    }

    @Override
    public List<AdminInfoVO> getList() {
        List<Admin> list = adminMapper.selectList(null);
        List<AdminInfoVO> ans = new ArrayList<>();
        for (Admin admin : list) {
            AdminInfoVO adminInfoVO = new AdminInfoVO();
            BeanUtils.copyProperties(admin, adminInfoVO);
            ans.add(adminInfoVO);
        }
        return ans;
    }

    @Override
    public void addNew(AdminAddDTO adminAddDTO) {
        if (adminAddDTO.getDescription() == null || adminAddDTO.getPassword() == null
                || adminAddDTO.getUsername() == null) {
            throw new BBSServiceException(ResponseCode.BAD_REQUEST, "参数不能为空");
        }
        //描述只能选择数据里有的,即角色名字
        System.out.println(adminAddDTO.getDescription()+"描述");
        QueryWrapper<Role> roleQueryWrapper = new QueryWrapper<Role>();
        roleQueryWrapper.eq("name", adminAddDTO.getDescription());
        Role role = roleMapper.selectOne(roleQueryWrapper);
        if (role==null){
            throw new BBSServiceException(ResponseCode.NOT_FOUND,"所选择的角色不存在！");
        }
        Long roleId = role.getId();

        QueryWrapper<Admin> wrapper = new QueryWrapper<>();
        wrapper.eq("username", adminAddDTO.getUsername());
        Admin admin = adminMapper.selectOne(wrapper);
        if (admin != null) {
            throw new BBSServiceException(ResponseCode.CONFLICT, "用户名已存在");
        }
        admin = new Admin();
        BeanUtils.copyProperties(adminAddDTO, admin);
        admin.setPassword(passwordEncoder.encode(admin.getPassword()));
        adminMapper.insert(admin);

        Long adminId = admin.getId();
        AdminRole adminRole = new AdminRole();
        adminRole.setAdminId(adminId);
        adminRole.setRoleId(roleId);
        adminRoleMapper.insert(adminRole);

    }

    @Override
    public int setEnableOrDis(Admin admin) {
        if (admin==null){
            throw new BBSServiceException(ResponseCode.BAD_REQUEST,"参数不能为空");
        }

        adminMapper.updateById(admin);
        return admin.getEnable();
    }

    @Override
    public void updateRole(Admin admin) {
        if (admin.getDescription()==null||admin.getUsername()==null){
            throw new BBSServiceException(ResponseCode.BAD_REQUEST,"参数不能为空");
        }
        //描述对应角色名字，获取角色id
        QueryWrapper<Role> roleQueryWrapper = new QueryWrapper<>();
        roleQueryWrapper.eq("name",admin.getDescription());
        Role role = roleMapper.selectOne(roleQueryWrapper);
        if (role==null){
            throw new BBSServiceException(ResponseCode.NOT_FOUND,"角色不存在！");
        }
        Long roleId = role.getId();
        //删除管理员角色关联表中的数据，重新增加角色
        QueryWrapper<AdminRole> adminRoleQueryWrapper = new QueryWrapper<>();
        adminRoleQueryWrapper.eq("admin_id",admin.getId());
        adminRoleMapper.delete(adminRoleQueryWrapper);

        AdminRole adminRole = new AdminRole();
        adminRole.setRoleId(roleId);
        adminRole.setAdminId(admin.getId());
        adminRoleMapper.insert(adminRole);

        //修改管理员的描述
        adminMapper.updateById(admin);
    }

    @Transactional
    @Override
    public void deleteById(Long id) {
        if (id==null){
            throw new BBSServiceException(ResponseCode.BAD_REQUEST,"参数不能为空");
        }
        Admin admin = adminMapper.selectById(id);
        //不存在不允许删除
        if (admin==null){
            throw new BBSServiceException(ResponseCode.NOT_FOUND,"管理员不存在");
        }
        //先删除管理员表
        adminMapper.deleteById(id);
        //删除管理员角色关联表
        QueryWrapper<AdminRole> roleQueryWrapper = new QueryWrapper<>();
        roleQueryWrapper.eq("admin_id",id);
        adminRoleMapper.delete(roleQueryWrapper);
    }
}
